#include "common.h"

int sockfd ;
struct sockaddr_in addr;
short PORT = 1234;
char *IP = "127.0.0.1";

struct client
{
	int fd;
	char name[BUFSIZE];
}client;

struct client c[MAXNUMOFPEOPLE] = {0};

//索引
int num;

//初始化
void init()
{
	printf("准备启动服务器...\n");
	if((sockfd = socket(PF_INET , SOCK_STREAM , 0)) == -1)
		perror("socket创建失败") , exit(-1);
	memset(&addr , 0 , sizeof(addr));
	addr.sin_family = PF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = INADDR_ANY;

	int reuseaddr = 1;
	setsockopt(sockfd , SOL_SOCKET, SO_REUSEADDR,&reuseaddr,sizeof(reuseaddr));

	if(bind(sockfd , (struct sockaddr *)&addr , sizeof(addr)) == -1)
		perror("服务器绑定失败") , exit(-1);
	listen(sockfd,5);
	printf("服务器成功启动...\n");
}

//群发消息
void sendtoAll(const char *buf , int fd)
{
	printf("buf = %s\n",buf);
	int i ;
	for(i = 0 ; i < num ; ++i)
	{
		if(fd != c[i].fd)
			send(c[i].fd , buf , strlen(buf) , 0);
	}
}

//加入成员
int join(int sockfd , char name[])
{
	int i = 0;
	for( ; i < num ; ++i)
	{
		if(c[i].fd == sockfd)
			return i;
	}
	//如果没找到，则添加一个新的账户
	//如果人数超过最大值，则返回错误
	if(num == MAXNUMOFPEOPLE)
	{
		return -1;
	}
	//新添加一个
	c[num].fd = sockfd;
	strcpy(c[num].name , name);	
	++num;
	return num - 1;
}

//离开房间
void leave(int sockfd)
{
	int i ;
	int index = 0;
	for(i = 0 ; i < num ; ++i)
	{
		if(c[i].fd == sockfd)
		{
			index = i;
			break;
		}
	}
	
	for(i = index ; i < num + 1 ; ++i)
	{
		c[i] = c[i+1];
	}
	--num;
}

//起一个线程用于接受客户端发来的消息
void* thread_recv(void *p)
{
	//当前用户数组的索引
	int cur = *(int *)p;
	
	char recvbuf[BUFSIZE] = {};
	char name[NAMELENTH] = {};
	char buf[BUFSIZE] = {};

	//printf("cur = %d , fd = %d , name = %s\n", cur,c[cur].fd , c[cur].name);

	while(1)
	{
		memset(buf , 0 , sizeof(buf));
		memset(recvbuf , 0 , sizeof(recvbuf));
		
		if( recv(c[cur].fd , recvbuf , sizeof(recvbuf) , 0) <= 0 )
		{
			//printf("[%s]离开了聊天室\n" , c[cur].name);
			sprintf(buf , "[%s]离开了聊天室" , c[cur].name);
			sendtoAll(buf , c[cur].fd);
			close(c[cur].fd);
			leave(c[cur].fd);
			return;		
		}
		sprintf(buf , "[%s]说:%s" , c[cur].name , recvbuf);		
		printf("%s说:%s\n" , c[cur].name , recvbuf);		
		//fflush(stdout);
		sendtoAll(buf , c[cur].fd);
	}
}

//服务器的业务逻辑
void service()
{
	//1、接受客户端发来的请求
	socklen_t len = sizeof(addr);
	struct sockaddr_in addrclient = {};
	char name[BUFSIZE] = {};
	char buf[BUFSIZE] = {};
	printf("***************\n");
	while(1)
	{	
		//接受客户端请求	
		memset(&addrclient , 0 , sizeof(addrclient));
		memset(name , 0 , sizeof(name));
		memset(buf , 0 , sizeof(buf));		
		int newsock = accept(sockfd , (struct sockaddr *)&addrclient , &len);
		recv(newsock , name , sizeof(name) , 0);
		int cur = join(newsock , name);
		printf("%s进入房间...\n", name);

		if(cur == -1)
		{
			sprintf(buf , "房间人满，请稍后...");
			send(newsock , buf , strlen(buf) , 0);			
		}
		else
		{
			//群发欢迎消息
			sprintf(buf , "欢迎 %s 加入！" , c[cur].name);

			sendtoAll(buf , -1);
			
			//针对此客户请求，启动线程接受此用户消息
			pthread_t id;			
			pthread_create(&id , 0 , thread_recv , (void *)&cur);
		}	
		
	}
}

//退出处理
void quit()
{
	close(sockfd);
	printf("关闭服务器...\n");
	exit(0);
}

int main()
{
	//信号量，增加一个信号量
	signal(SIGINT,quit);
	init();
	service();
	quit();
}
